package cc.rengu.igas.route.core.realize.impl;

import cc.rengu.chargecalc.mchntfee.CalcMchntFeeCore;
import cc.rengu.chargecalc.mchntfee.dao.FeeInfoMapper;
import cc.rengu.chargecalc.mchntfee.dao.impl.FeeInfoMapperImpl;
import cc.rengu.chargecalc.mchntfee.entity.FeeInfoObj;
import cc.rengu.chargecalc.mchntfee.util.Database.ConnectDB;
import cc.rengu.chargecalc.mchntfee.util.Database.DatabaseOpr;
import cc.rengu.igas.route.common.constant.SmartRouteParamConstant;
import cc.rengu.igas.route.common.entity.WeightCfg;
import cc.rengu.igas.route.common.enums.RouteTxnNumEnum;
import cc.rengu.igas.route.common.enums.SmartRouteRspEnums;
import cc.rengu.igas.route.core.model.CompleteRouteInfoBean;
import cc.rengu.igas.route.core.model.CompleteSmartRouteInfo;
import cc.rengu.igas.route.core.model.ProdInfoBean;
import cc.rengu.igas.route.facade.bean.CalChannelInfo;
import cc.rengu.igas.route.facade.bean.CalChannelInfoReq;
import cc.rengu.igas.route.facade.request.IntelliCalRequest;
import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.dao.ChannelCallCfgMapper;
import cc.rengu.oltp.service.common.dao.DstChannelInfoMapper;
import cc.rengu.oltp.service.common.dao.DstTxnAuthCfgMapper;
import cc.rengu.oltp.service.common.dao.impl.ChannelCallCfgMapperImpl;
import cc.rengu.oltp.service.common.dao.impl.DstChannelInfoMapperImpl;
import cc.rengu.oltp.service.common.dao.impl.DstTxnAuthCfgMapperImpl;
import cc.rengu.oltp.service.common.entity.ChannelCallCfg;
import cc.rengu.oltp.service.common.entity.DstChannelInfo;
import cc.rengu.oltp.service.common.entity.DstTxnAuthCfg;
import cc.rengu.oltp.service.common.entity.SysParam;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.service.realize.SysParamService;
import cc.rengu.oltp.service.realize.impl.SysParamServiceImpl;
import cc.rengu.oltp.utility.util.AmountUtil;
import cc.rengu.oltp.utility.util.DateUtil;
import cc.rengu.oltp.utility.util.RedisUtil;
import cc.rengu.oltp.utility.util.StringUtil;
import cc.rengu.utility.log.RgLog;
import cc.rengu.utility.log.RgLogger;
import com.alibaba.fastjson.JSON;

import java.sql.Connection;
import java.util.*;

/**
 * 智能路由实现类
 *
 * @author xionglz
 * @version 1.0
 * @date 2020-03-23
 */
public class WeightCfgRouterChoice4POCImpl {
    private static final Double zeroD = Double.parseDouble("0.000");
    private RgLogger rglog = RgLog.getLogger(this.getClass().getName());

    private Double feeMinD;
    private Map<String, String> mapFee;
    private boolean feeIsZero = false;
    private CompleteSmartRouteInfo completeSmartRouteInfo;

    /**
     * 智能路由选择
     *
     * @return 路由成功返回按照得分从高到底排序的可能的通道，null或者size为0路由失败
     * @throws Exception 其他异常
     */
    public List<CalChannelInfo> routerChoice(IntelliCalRequest request) throws Exception {
        Map<String, CalChannelInfo> calChannelInfoMap = new HashMap<>();
        List<CalChannelInfo> calChannelInfos = new ArrayList<>();
        //1. 装载配置信息
        loadSmartCfg(request, calChannelInfoMap);
        //2. 计算费用，设置到map中
        calculateCost("100.00", calChannelInfoMap);
        //4. 循环计算得分
        List<ProdInfoBean> listProdInfo = getAllScore(calChannelInfoMap);
        //5. 查询模式，返回得分列表
        //5.1.listProdInfo经过上面的过滤不可能存在不需要签约且要素不齐全的通道;只有可能为空,为空则返回失败
        //5.2.获取listProdInfo中需要签约的条数,已签约的条数,不需要签约(不需要签约的验证要素一定是齐全的)的条数
        if (listProdInfo.isEmpty()) {
            rglog.error("无可用通道");
            throw new BizException(SmartRouteRspEnums.NO_AVAILABLE_DST_CHANNEL_ERROR.getRespCode(),
                    SmartRouteRspEnums.NO_AVAILABLE_DST_CHANNEL_ERROR.getRespDesc());
        }

        //7. 进行排序
        listProdInfo.sort((o1, o2) -> -Double.compare(Double.parseDouble(o1.getPriority()), Double.parseDouble(o2.getPriority())));
        listProdInfo.forEach(item -> rglog.debug("通道{},得分{}", item.getDstChannelId(), item.getPriority()));
        //8. 若通道数量大于等于2，则只判断头两条通道的得分是否一致，如果一致则根据其优先级在优先级高的得分+1
        switch (request.getQryTxnNum()) {
            case "T00CP015":
                //鉴权
                procEqualScore(listProdInfo, request.getHeader().getInstId(), RouteTxnNumEnum.PAYMENT_SIGN.getTxnGroup());
                break;
            case "P01CP003":
                //代收
                procEqualScore(listProdInfo, request.getHeader().getInstId(), RouteTxnNumEnum.PAYMENT.getTxnGroup());
                break;
            case "P01CP004":
            default:
                //代付
                procEqualScore(listProdInfo, request.getHeader().getInstId(), RouteTxnNumEnum.CREDIT.getTxnGroup());
                break;
        }
        calChannelInfos.addAll(calChannelInfoMap.values());
        int i = 0;
        for (ProdInfoBean prodInfoBean : listProdInfo) {
            //key: ROUT_MONITOR+qryTxnNum（查询的交易类型）+qryTBizType（查询的原业务分类）
            //field: dstChannelId（通道产品编码）+|+channelDesc（通道描述）+|+feeWeight（费用权重）+|+stressWeight（压力权重）+|+succRateWeight（交易成功率权重）+|+timeCostWeight（响应时间权重）
            String key = SmartRouteParamConstant.ROUT_MONITOR + request.getQryTxnNum() + request.getQryBizType();
            String f = prodInfoBean.getDstChannelId() + "|" + calChannelInfoMap.get(prodInfoBean.getDstChannelId()).getChannelDesc() + "|" + request.getFeeWeight() + "|" + request.getStressWeight() + "|" + request.getSuccRateWeight() + "|" + request.getTimeCostWeight();
            rglog.info("key={},field={}", key, f);
            if (i == 0) {
                //入到redis，XX交易 XX模型（以权重表示）总交易笔数 XX通道交易笔数
                RedisUtil.hashIncrease(key, f, 1);
            } else {
                RedisUtil.hashIncrease(key, f, 0);
            }
            i++;
        }
        return calChannelInfos;
    }

    /**
     * 装载智能路由配置
     *
     * @throws Exception 失败
     */
    private void loadSmartCfg(IntelliCalRequest request, Map<String, CalChannelInfo> calChannelInfoMap) throws Exception {
        WeightCfg weightCfg = new WeightCfg();
        weightCfg.setInstId(request.getHeader().getInstId());
//        weightCfg.setRuleId(0);
        weightCfg.setFeeCostWeight(Integer.parseInt(request.getFeeWeight()));
        weightCfg.setStressWeight(Integer.parseInt(request.getStressWeight()));
        weightCfg.setSuccRateWeight(Integer.parseInt(request.getSuccRateWeight()));
        weightCfg.setTimeCostWeight(Integer.parseInt(request.getTimeCostWeight()));
//        weightCfg.setRuleStatus("");
//        weightCfg.setAuditStatus("");
//        weightCfg.setRecordStopReason("");
//        weightCfg.setAuditRefuseReason();
//        weightCfg.setOprId();
//        weightCfg.setCreateTime();
//        weightCfg.setLastOprId();
//        weightCfg.setLastUpdateTime();
//        weightCfg.setLastAuditId();
//        weightCfg.setLastAuditTime();
//        weightCfg.setId();
//        weightCfg.setRemark1();
//        weightCfg.setRemark2();
//        weightCfg.setRemark3();


        completeSmartRouteInfo = new CompleteSmartRouteInfo(weightCfg);
        //检查交易渠道在能力开放完成，检查交易通道在智能路由完成
        //查询redis，不存在或者失败再降级查询数据库
        ChannelCallCfgMapper channelCallCfgMapper = new ChannelCallCfgMapperImpl();
        List<ChannelCallCfg> channelCallCfgs = channelCallCfgMapper.selectChannelCallCfgByTxnNum(request.getHeader().getInstId(), SmartRouteParamConstant.IGRT,
                SmartRouteParamConstant.ALL, request.getQryTxnNum(), SmartRouteParamConstant.STRING_TWO_ZERO);
        Optional.ofNullable(channelCallCfgs).orElseThrow(() -> {
            rglog.error("获取交易码映射表失败");
            return new BizException(SmartRouteRspEnums.CONFIG_ERROR.getRespCode(), SmartRouteRspEnums.CONFIG_ERROR.getRespDesc());
        });
        for (ChannelCallCfg channelCallCfg : channelCallCfgs) {
            rglog.warn("该通道<{}：{}：{}>", channelCallCfg.getInstId(), channelCallCfg.getCallChannelId(), channelCallCfg.getCallChannelTxn());
            //获取通道信息
            DstChannelInfo dstChannelInfo = null;
            String dstChannelInfoKey = channelCallCfg.getInstId().trim() + channelCallCfg.getCallChannelId().trim();
            try {
                dstChannelInfo = JSON.parseObject(RedisUtil.hashGet(AppParamConstant.CHANNEL_ISS_INFO_CACHE, dstChannelInfoKey), DstChannelInfo.class);
            } catch (Exception e) {
                rglog.warn("redis中未查询到key<{}>通道信息", dstChannelInfoKey);
            }
            if (null == dstChannelInfo) {
                DstChannelInfoMapper dstChannelInfoMapper = new DstChannelInfoMapperImpl();
                dstChannelInfo = dstChannelInfoMapper.selectDstChannelInfoByPrimaryKey(channelCallCfg.getInstId().trim(), channelCallCfg.getCallChannelId().trim());
            }
            if (null == dstChannelInfo) {
                //未配置该通道
                rglog.warn("该通道<{}：{}>未配置通道信息", channelCallCfg.getInstId(), channelCallCfg.getCallChannelId());
                continue;
            }
            //排除本行通道
            if (SmartRouteParamConstant.ESB.equalsIgnoreCase(dstChannelInfo.getDstChannelId()) ||
                    SmartRouteParamConstant.ESBMS.equalsIgnoreCase(dstChannelInfo.getDstChannelId())) {
                continue;
            }
            //获取通道交易权限信息
            DstTxnAuthCfg dstTxnAuthCfg = null;
            String dstTxnAuthKey = SmartRouteParamConstant.ROUTE_CONF_DST_TXN_AUTH + ":" + channelCallCfg.getInstId() + ":" + channelCallCfg.getCallChannelId() + ":" + channelCallCfg.getCallChannelTxn();
            try {
                dstTxnAuthCfg = JSON.parseObject(RedisUtil.onceGet(dstTxnAuthKey), DstTxnAuthCfg.class);
            } catch (Exception e) {
                rglog.warn("redis中未查询到key<{}>通道交易权限信息", dstTxnAuthKey);
            }
            if (null == dstTxnAuthCfg) {
                //查询数据库
                DstTxnAuthCfgMapper dstTxnAuthCfgMapper = new DstTxnAuthCfgMapperImpl();
                dstTxnAuthCfg = dstTxnAuthCfgMapper.selectDstTxnAuthCfgByPrimaryKey(channelCallCfg.getInstId(), channelCallCfg.getCallChannelId(), channelCallCfg.getCallChannelTxn());
            }
            if (null == dstTxnAuthCfg) {
                rglog.warn("该通道<{}：{}：{}>没有配置支持智能路由的通道交易", channelCallCfg.getInstId(), channelCallCfg.getCallChannelId(), channelCallCfg.getCallChannelTxn());
                continue;
            }

            CompleteRouteInfoBean completeRouteInfoBean = new CompleteRouteInfoBean(dstChannelInfo, channelCallCfg, dstTxnAuthCfg);
//            completeRouteInfoBean.setDstChannelTxnImplClassName(sysParam.getParamValue());
            String beanKey = completeRouteInfoBean.getDstChannelInfo().getInstId().trim() + ":" + completeRouteInfoBean.getDstChannelInfo().getDstChannelId() + ":" + completeRouteInfoBean.getChannelCallCfg().getTxnNum();
            completeSmartRouteInfo.getAvailDstChannels().put(beanKey, completeRouteInfoBean);
            String dstChannelId = dstChannelInfo.getDstChannelId();
            Optional<CalChannelInfoReq> calChannelInfoReqOpt = request.getCalChannelInfoReqList().stream().
                    filter(item -> item.getDstChannelId().equals(dstChannelId)).findFirst();
            if (calChannelInfoReqOpt.isPresent()) {
                CalChannelInfo calChannelInfo = new CalChannelInfo();
                calChannelInfo.setDstChannelId(dstChannelInfo.getDstChannelId());
                calChannelInfo.setChannelDesc(dstChannelInfo.getDstChannelName());
                calChannelInfo.setChannelFeeRate(dstTxnAuthCfg.getChannelTxnRate());
                calChannelInfo.setSuccRate(calChannelInfoReqOpt.get().getSuccRate());
                calChannelInfo.setStress(calChannelInfoReqOpt.get().getStress());
                calChannelInfo.setTimeCost(calChannelInfoReqOpt.get().getTimeCost());
                calChannelInfoMap.put(dstChannelInfo.getDstChannelId(), calChannelInfo);
            }
        }

        if (completeSmartRouteInfo.getAvailDstChannels().isEmpty()) {
            rglog.error("无可用通道");
            throw new BizException(SmartRouteRspEnums.NO_AVAILABLE_DST_CHANNEL_ERROR.getRespCode(), SmartRouteRspEnums.NO_AVAILABLE_DST_CHANNEL_ERROR.getRespDesc());
        }
    }


    /**
     * 计算通道所有维度总体得分
     *
     * @param dstChannelInfo 通道信息
     * @param weightCfg      智能路由配置的各维度的占比
     * @return 通道得分
     */
    private double getTotalScore(DstChannelInfo dstChannelInfo, WeightCfg weightCfg, Map<String, CalChannelInfo> calChannelInfoMap) {
        CalChannelInfo calChannelInfo = calChannelInfoMap.get(dstChannelInfo.getDstChannelId());
        if (null == calChannelInfo) {
            return 0;
        }
        String fee = mapFee.get(dstChannelInfo.getDstChannelId());
        if (StringUtil.isEmptyOrNull(fee)) {
            return 0;
        }
        double feePer = getFeePercent(fee);

        double avgStressPer = getStressPercent(Integer.parseInt(calChannelInfo.getStress()));
        //该成功率已经乘以100
        double succRatePer = Double.parseDouble(calChannelInfo.getSuccRate());
        //响应时间，即相较于标准的偏差可以正负
        double costTimePer = getTimePercent(Double.parseDouble(calChannelInfo.getTimeCost()));
        calChannelInfo.setFeeScore(String.format("%.2f", feePer));
        calChannelInfo.setStressScore(String.format("%.2f", avgStressPer));
        calChannelInfo.setSuccRateScore(String.format("%.2f", succRatePer));
        calChannelInfo.setTimeCostScore(String.format("%.2f", costTimePer));
        //根据权重计算总分
        double percentTotal = (weightCfg.getFeeCostWeight() / 100.0) * feePer +
                (weightCfg.getStressWeight() / 100.0) * avgStressPer +
                (weightCfg.getSuccRateWeight() / 100.0) * succRatePer +
                (weightCfg.getTimeCostWeight() / 100.0) * costTimePer;
        String percentTotalStr = String.format("%.2f", percentTotal);
        rglog.debug("通道<{}:{}><费用占比:{}%>,<压力占比:{}%>,<成功率占比:{}%>,<响应时间占比:{}%>",
                dstChannelInfo.getDstChannelId(), dstChannelInfo.getDstChannelName(), weightCfg.getFeeCostWeight(),
                weightCfg.getStressWeight(), weightCfg.getSuccRateWeight(), weightCfg.getTimeCostWeight());
        rglog.debug("通道<{}:{}><费用得分:{}>,<压力得分:{}>,<成功率得分:{}>,<响应时间得分:{}>",
                dstChannelInfo.getDstChannelId(), dstChannelInfo.getDstChannelName(), feePer, avgStressPer, succRatePer, costTimePer);
        calChannelInfo.setTotalScore(percentTotalStr);
        return percentTotal;
    }

    /**
     * 处理得分一致的通道
     *
     * @param listProdInfo 按照优先级从大到小排序后的可能的通道列表
     */
    private void procEqualScore(List<ProdInfoBean> listProdInfo, String instId, String txnGroup) {
        if (null != listProdInfo && listProdInfo.size() >= 2) {
            try {
                ProdInfoBean firstProd = listProdInfo.get(0);
                ProdInfoBean secondProd = listProdInfo.get(1);
                double firstPriority = Double.parseDouble(firstProd.getPriority());
                double secondPriority = Double.parseDouble(secondProd.getPriority());
                //头两条得分一致，使用优先级判断顺序
                if (firstPriority - secondPriority <= 0.0005) {
                    SysParamService sysParamService = new SysParamServiceImpl();
                    SysParam sysParam = sysParamService.getSysParamInfo(instId, SmartRouteParamConstant.ROUTE_CONF_PRIO, txnGroup);
                    //能够查询到数据切数据有效使用配置的优先级，否则不变更现有的顺序
                    if (null != sysParam && SmartRouteParamConstant.YES.equals(sysParam.getParamStatus())) {
                        String proValue = sysParam.getParamValue();
                        rglog.info("优先级为<{}>", proValue);
                        int indexFirst = proValue.indexOf(firstProd.getDstChannelId());
                        int indexSecond = proValue.indexOf(secondProd.getDstChannelId());
                        //第一条的优先级低于第二条,互换位置
                        if (indexFirst > indexSecond) {
                            rglog.info("互换通道<{}:{}>优先级", firstProd.getDstChannelId(), secondProd.getDstChannelId());
                            listProdInfo.set(0, secondProd);
                            listProdInfo.set(1, firstProd);
                        }
                        double highest = Double.parseDouble(firstProd.getPriority()) + 1;
                        listProdInfo.get(0).setPriority(Double.valueOf(highest).toString());
                    }
                }
            } catch (Exception e) {
                rglog.warn(cc.rengu.utility.base.StringUtil.ExceptionToString(e));
            }
        }
    }

    /**
     * 计算成本得分
     *
     * @param nowFee 当前费用
     * @return
     */
    private double getFeePercent(String nowFee) {
        double feePer;
        Double nowFeeD = Double.parseDouble(nowFee);
        int ret = nowFeeD.compareTo(zeroD);
        //当前费用比最低费用的差
        //最低费用为0则不为0的所有的费用得分都为0
        if (feeIsZero && ret != 0) {
            feePer = 0;
        }
        //最低费用为0则为0的所有的费用得分都为100
        else if (feeIsZero) {
            feePer = 100;
        } else {
            feePer = 100.00 - ((nowFeeD - feeMinD) / feeMinD) * 100.00;
        }
        rglog.info("当前费用<{}>,最低费用<{}>,费用得分<{}>", nowFeeD, feeMinD, feePer);
        return feePer;
    }

    /**
     * 计算通道压力得分
     *
     * @param stress 压力
     * @return
     */
    private double getStressPercent(int stress) {
        //如果基准值即最大支持交易笔数为0则为未配置，设置基准的压力值为100
        //压力80%以下都为满分
        double stressPer = 100;
        if (stress > 80) {
            stressPer = 100 - stress;
        }
        rglog.debug(" 当前压力值（相对于基准压力）<{}%>, 压力单项分数<{}>", stress, stressPer);
        return stressPer;
    }

    /**
     * 计算响应时间得分
     *
     * @param gap 偏差的百分比，正偏差指大于基准时间，负偏差指小于基准时间
     * @return
     */
    private double getTimePercent(double gap) {

        //未配置通道的响应时间则设置默认的基准时间为60秒
        double timePer = 100;
        if (0 < gap) {
            timePer = 100 - gap;
        }
        rglog.debug("与基准时间的偏差<{}%>, 响应时间单项分数<{}>", gap, timePer);
        return timePer;
    }

    /**
     * 获取map中值最小的值
     *
     * @return java.lang.Double
     **/
    private String getMinValue() {
        Collection<String> c = mapFee.values();
        Object[] obj = c.toArray();
        Arrays.sort(obj);
        return obj[0].toString();
    }

    /**
     * 计算每个通道的费用
     *
     * @param amt 交易金额
     * @throws Exception 失败
     */
    private void calculateCost(String amt, Map<String, CalChannelInfo> calChannelInfoMap) throws Exception {
        mapFee = new HashMap<>();
        //如果不上送交易金额则所有通道的费用都为0，费用得分都为100分
        FeeInfoMapper feeInfoMapper = new FeeInfoMapperImpl();
        CalcMchntFeeCore calcMchntFee = new CalcMchntFeeCore();
        DatabaseOpr database = new DatabaseOpr();
        Connection connection = database.getDbConnection();
        if (connection == null) {
            rglog.error("获取数据库链接失败");
            throw new BizException(SmartRouteRspEnums.TRANS_FAIL.getRespCode(), SmartRouteRspEnums.TRANS_FAIL.getRespDesc());
        }
        try {
            for (CompleteRouteInfoBean completeRouteInfoBean : completeSmartRouteInfo.getAvailDstChannels().values()) {
                rglog.warn("计算通道交易<{}：{}：{}>费用", completeRouteInfoBean.getChannelCallCfg().getInstId(), completeRouteInfoBean.getChannelCallCfg().getCallChannelId(), completeRouteInfoBean.getChannelCallCfg().getCallChannelTxn());
                if (cc.rengu.utility.base.StringUtil.isNullorEmpty(amt)) {
                    mapFee.put(completeRouteInfoBean.getChannelCallCfg().getCallChannelId(), "0.000");
                    continue;
                }
                if (0 == AmountUtil.compare(amt, "0")) {
                    mapFee.put(completeRouteInfoBean.getChannelCallCfg().getCallChannelId(), "0.000");
                    continue;
                }
                //未配置费率模板费率以0计算
                if (StringUtil.isEmptyOrNull(completeRouteInfoBean.getDstTxnAuthCfg().getChannelTxnRate())) {
                    rglog.info("通道交易<{}:{}:{}>未配置费率费用直接以0计算", completeRouteInfoBean.getChannelCallCfg().getInstId(), completeRouteInfoBean.getChannelCallCfg().getCallChannelId(), completeRouteInfoBean.getChannelCallCfg().getCallChannelTxn());
                    mapFee.put(completeRouteInfoBean.getChannelCallCfg().getCallChannelId(), "0.000");
                } else {
                    //查询费率模板表
                    List<FeeInfoObj> listFeeInfoObj = feeInfoMapper.getFeeInfoByFeeCode(completeRouteInfoBean.getDstTxnAuthCfg().getChannelTxnRate(), DateUtil.getCurrentDate(), completeRouteInfoBean.getChannelCallCfg().getInstId(), connection);
                    Optional.ofNullable(listFeeInfoObj).orElseThrow(() -> {
                        rglog.error("费率模板表未配置,<Feeid:{}>", completeRouteInfoBean.getDstTxnAuthCfg().getChannelTxnRate());
                        return new BizException(SmartRouteRspEnums.CONFIG_ERROR.getRespCode(), SmartRouteRspEnums.CONFIG_ERROR.getRespDesc());
                    });
                    //计算费用
                    String fee = calcMchntFee.feeCdCharging(amt, listFeeInfoObj);
                    if (StringUtil.isEmptyOrNull(fee)) {
                        rglog.error("费用计算失败,<Feeid:{}>", completeRouteInfoBean.getDstTxnAuthCfg().getChannelTxnRate());
                        continue;
                        //                        throw new BizException(SmartRouteRspEnums.TRANS_FAIL.getRespCode(), SmartRouteRspEnums.TRANS_FAIL.getRespDesc());
                    }
                    rglog.info("通道<{}>,交易<{}>,费用模板<{}>,交易金额<{}>,费用<{}>", completeRouteInfoBean.getChannelCallCfg().getCallChannelId(),
                            completeRouteInfoBean.getChannelCallCfg().getCallChannelTxn(), completeRouteInfoBean.getDstTxnAuthCfg().getChannelTxnRate(), amt, fee);
                    mapFee.put(completeRouteInfoBean.getChannelCallCfg().getCallChannelId(), fee);
                }
            }
        } finally {
            ConnectDB.closeConn(connection);
        }


        //所有通道都被滤掉
        if (mapFee.isEmpty()) {
            rglog.error("所有通道都被滤掉,交易失败");
            throw new BizException(SmartRouteRspEnums.CONFIG_ERROR.getRespCode(), SmartRouteRspEnums.CONFIG_ERROR.getRespDesc());
        }
        if (completeSmartRouteInfo.getAvailDstChannels().isEmpty()) {
            rglog.error("所有通道都被滤掉,交易失败");
            throw new BizException(SmartRouteRspEnums.CONFIG_ERROR.getRespCode(), SmartRouteRspEnums.CONFIG_ERROR.getRespDesc());
        }
        //得到最小值
        String feeMin = getMinValue();
        feeMinD = Double.parseDouble(feeMin);
        rglog.info("最低费用为<{}>", feeMinD);
        //最低手续费为0的情况
        if (feeMinD.compareTo(zeroD) == 0) {
            feeIsZero = true;
        }
    }

    /**
     * 获取所有可用通道的得分
     *
     * @return 产品列表
     * @throws Exception 异常
     */
    private List<ProdInfoBean> getAllScore(Map<String, CalChannelInfo> calChannelInfoMap) throws Exception {
        List<ProdInfoBean> listProdInfo = new ArrayList<>();
        //循环计算每条通道的得分
        for (CompleteRouteInfoBean bean : completeSmartRouteInfo.getAvailDstChannels().values()) {
            //判断系统缓存中是否有该条通道的动态统计数据,系统加载时创建所有通道Redis缓存的动态数据
            double score = getTotalScore(bean.getDstChannelInfo(), completeSmartRouteInfo.getWeightCfg(), calChannelInfoMap);
            ProdInfoBean prodInfo = new ProdInfoBean();
            prodInfo.setDelayedFlag("");
            prodInfo.setDstChannelId(bean.getDstChannelInfo().getDstChannelId());
            prodInfo.setFee(mapFee.get(bean.getDstChannelInfo().getDstChannelId()));
            prodInfo.setNeedSign(bean.getDstTxnAuthCfg().getNeedSignFlag());
            prodInfo.setPriority(String.valueOf(score));
            prodInfo.setProdDesc(bean.getDstTxnAuthCfg().getTxnName());
            prodInfo.setProdSts(bean.getDstChannelInfo().getDstChannelStatus());
//            prodInfo.setSignSt();
            prodInfo.setDstChannelTxnImplClassName(bean.getDstChannelTxnImplClassName());
            prodInfo.setDstChannelTxnNum(bean.getDstTxnAuthCfg().getChannelTxn());
            listProdInfo.add(prodInfo);
        }
        return listProdInfo;
    }
}
